package masterjava.common.dao.hibernate;

import masterjava.common.dao.GenericDao;
import masterjava.common.shared.entity.GenericEntity;
import masterjava.common.util.Util;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.List;

/**
 * Extended flexible Hibernate operation, coudn't be implemented via HibernateDaoHelper/ClientDaoRpcManager
 *
 * @param <T>  entity
 * @param <ID> primary key
 */
public abstract class GenericHibernateDao<T extends GenericEntity<ID>, ID extends Serializable> implements GenericDao<T, ID> {

    protected Class<T> persistentClass;

    @Autowired
    private HibernateDaoHelper hibernateDaoHelper;

    protected GenericHibernateDao() {
        persistentClass = Util.getGenericParameter(this, 0);
    }

    protected Session getSession() {
        return hibernateDaoHelper.getSession();
    }

    @Override
    public List<T> loadAll() {
        return hibernateDaoHelper.loadAll(persistentClass);
    }

    @Override
    public Criteria getRootCriteria() {
        return hibernateDaoHelper.getRootCriteria(persistentClass);
    }

    @Override
    public List<T> list(Criteria c) {
        return hibernateDaoHelper.list(c);
    }

    @Override
    public List<T> list(Query q) {
        return hibernateDaoHelper.list(q);
    }

    /* return initialized entity */
    public T get(ID id) {
        return hibernateDaoHelper.get(persistentClass, id);
    }

    /* return uninitialized entity */
    public T load(ID id) {
        return hibernateDaoHelper.load(persistentClass, id);
    }

    @Override
    public void delete(T entity) {
        hibernateDaoHelper.delete(entity);
    }

    @Override
    @SuppressWarnings("unchecked")
    public ID saveOrUpdate(T entity) {
        return (ID) hibernateDaoHelper.saveOrUpdate(entity);
    }

    @Override
    public void refresh(T entity) {
        getSession().refresh(entity);
    }

    @Override
    public void flush() {
        getSession().flush();
    }

    @Override
    public Query getNamedQuery(String queryName) {
        return getSession().getNamedQuery(queryName);
    }
}